using System;
using System.Configuration;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.SqlClient;
using System.Data.Common;
using System.Net;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using System.Data;
using System.Xml;
using System.Timers;
using System.Windows.Forms;
using System.Web.Services.Protocols;

namespace Microsoft.EPM.TSAutoStatus
{
    public partial class TSService : ServiceBase
    {
        #region Constants
        private const string CONN_STR = "Data Source={0};Initial Catalog={1};Integrated Security=True";
        private const string LOG_PREFIX = "tsAutoStatus";
        #endregion

        #region Private Data
        private static bool logEvents = false;
        private static bool logFileEveryHour = true;
        private static string logFolder = "";
        private static string sspName;
        private static string hostName = "";
        private static bool submitStatus = false;
        private static EventEntry eventLog = new EventEntry();
        private static string dbServer;
        private static string dbName;
        private static string conn_str = "";
        private static string psurl;
        private static string startTime = "";
        private static string processingDuration = "";
        private static int timerInterval = 60000;
        private UpdateStatus status;
        private System.Timers.Timer pollTimer = new System.Timers.Timer();
        #endregion

        public TSService()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            LoadSettings();

            status = new UpdateStatus(psurl);
            status.LogFileEveryHour = logFileEveryHour;
            status.LoggingEnabled = logEvents;
            status.LoggingFolder = logFolder;
            status.LoggingPrefix = LOG_PREFIX;
            status.HostName = hostName;

            pollTimer.Elapsed += new ElapsedEventHandler(OnTimerEvent);

            pollTimer.Enabled = true;
            eventLog.WriteEvent("Timer enabled", EventLogEntryType.Information);
            pollTimer.Interval = timerInterval;
            eventLog.WriteEvent("Timer interval=" + pollTimer.Interval.ToString() + ", Start Time=" + startTime + ", Duration=" + processingDuration, EventLogEntryType.Information);
        }

        protected override void OnStop()
        {
            pollTimer.Enabled = false;
        }

        private void OnTimerEvent(object source, ElapsedEventArgs e)
        {
            try
            {
                if (!ReadyToProcess()) return;

                pollTimer.Enabled = false;

                using (SqlConnection cn = new SqlConnection(conn_str))
                {
                    cn.Open();
                    DataSet ds = RetrieveTimesheets(cn);

                    foreach (DataRow row in ds.Tables[0].Rows)
                    {
                        if (logEvents) eventLog.WriteEvent("siteGuid=" + row["siteGuid"].ToString() + ", tsGuid=" + row["tsGuid"].ToString(), EventLogEntryType.Information);
                        bool result = status.ProcessTimesheet((Guid)row["siteGuid"], (Guid)row["tsGuid"], row["lcid"].ToString(), row["userName"].ToString(), true, sspName);
                        if (logEvents) eventLog.WriteEvent("Update status on row " + row["ID"].ToString(), EventLogEntryType.Information);
                        UpdateStatus(cn, (int)row["ID"], result);
                    }
                }
            }
            catch (Exception ex)
            {
                eventLog.WriteEvent(ex.Message);
            }
            finally
            {
                status.FlushLog();
                pollTimer.Enabled = true;
            }
        }

        #region Private Methods
        private bool ReadyToProcess()
        {
            // If the processing window is defined, check if currently in that windows.
            int duration;
            DateTime start;
            DateTime end;
            DateTime now = DateTime.Now;
            if (startTime.Length > 0)
            {
                try
                {
                    start = Convert.ToDateTime(startTime);
                    duration = Convert.ToInt32(processingDuration);
                    end = start.AddHours(duration);
                }
                catch (Exception)
                {
                    return false;
                }

                return (now >= start && (now <= end || duration == 0));
            }
            return true;
        }

        private DataSet RetrieveTimesheets(SqlConnection cn)
        {
            try
            {
                DataSet ds = new DataSet();
                SqlCommand cmdRetrieve = new SqlCommand("tsGetUnprocessedTimesheets", cn);
                cmdRetrieve.CommandType = CommandType.StoredProcedure;
                SqlDataAdapter da = new SqlDataAdapter(cmdRetrieve);
                da.Fill(ds);
                return ds;
            }
            catch (Exception ex)
            {
                eventLog.WriteEvent(ex.Message);
                return null;
            }
        }

        private void UpdateStatus(SqlConnection cn, int ID, bool result)
        {
            try
            {
                SqlCommand cmdUpdate;
                if (result)
                {
                    cmdUpdate = new SqlCommand("tsSetTimesheetProcessed", cn);
                }
                else
                {
                    cmdUpdate = new SqlCommand("tsSetTimesheetFailed", cn);
                }
                cmdUpdate.CommandType = CommandType.StoredProcedure;
                SqlParameter parm = new SqlParameter("ID", SqlDbType.Int, 4);
                parm.Value = ID;
                cmdUpdate.Parameters.Add(parm);
                cmdUpdate.ExecuteNonQuery();
            }
            catch (Exception ex)
            {
                eventLog.WriteEvent(ex.Message);
            }
        }

        private void LoadSettings()
        {
            // Load settings from TSAutoStatus.exe.config
            try
            {
                XmlDocument doc = new XmlDocument();
                doc.Load(Application.ExecutablePath + ".config");
                XmlNode config = doc.SelectSingleNode("configuration");
                XmlNode appSettings = config.SelectSingleNode("applicationSettings");
                XmlNode app = appSettings.SelectSingleNode("Microsoft.EPM.TSAutoStatus.Properties.Settings");
                XmlNodeList items = app.SelectNodes("setting");
                XmlNode itemValue;
                foreach (XmlNode item in items)
                {
                    itemValue = item.SelectSingleNode("value");
                    switch (item.Attributes["name"].Value)
                    {
                        case "TimeInterval":
                            timerInterval = Convert.ToInt32(itemValue.InnerText);
                            break;

                        case "LogFolder":
                            logFolder = itemValue.InnerText;
                            break;

                        case "LogTimesheetEvent":
                            logEvents = Convert.ToBoolean(itemValue.InnerText);
                            break;

                        case "LogFileEveryHour":
                            logFileEveryHour = Convert.ToBoolean(itemValue.InnerText);
                            break;

                        case "PWASSPName":
                            sspName = itemValue.InnerText;
                            break;

                        case "AutomaticallySubmitStatusUpdate":
                            submitStatus = Convert.ToBoolean(itemValue.InnerText);
                            break;

                        case "DatabaseServer":
                            dbServer = itemValue.InnerText;
                            break;

                        case "DatabaseName":
                            dbName = itemValue.InnerText;
                            break;

                        case "PSURL":
                            psurl = itemValue.InnerText;
                            break;

                        case "HostName":
                            hostName = itemValue.InnerText;
                            break;

                        case "StartTime":
                            startTime = itemValue.InnerText.Trim();
                            break;

                        case "ProcessingDuration":
                            processingDuration = itemValue.InnerText.Trim();
                            break;
                    }
                    if (logEvents) eventLog.WriteEvent(item.Attributes["name"].Value + ", " + itemValue.InnerText, EventLogEntryType.Information);
                }
                conn_str = string.Format(CONN_STR, dbServer, dbName);
            }
            catch (Exception ex)
            {
                eventLog.WriteEvent(string.Format("Could not load settings from TSService.config: {0}", ex.Message));
            }
        }
        #endregion
    }
}
